package com.neulogistics.core.customercenter.api.application.command.handler;

import com.blackto.lib.mediat.unicast.IRequestHandler;
import com.neulogistics.core.customercenter.api.application.command.PlaceOrderCommand;
import com.neulogistics.core.customercenter.api.application.integrationevent.ICustomerCenterIntegrationEventService;
import com.neulogistics.infrastructure.common.annotation.ProduceEvent;
import com.neulogistics.infrastructure.integrationeventlog.model.IntegrationEventConstant;
import com.neulogistics.core.customercenter.api.application.integrationevent.publish.OrderPlacedIntegrationEvent;
import com.neulogistics.core.customercenter.api.service.ThreadLocalService;
import com.neulogistics.core.customercenter.domain.model.aggregate.Order;
import com.neulogistics.core.customercenter.domain.model.enumeration.OrderType;
import com.neulogistics.core.customercenter.domain.model.valueobject.Address;
import com.neulogistics.core.customercenter.domain.model.valueobject.OrderItem;
import com.neulogistics.core.customercenter.domain.service.ICustomerCenterDomainService;
import com.neulogistics.infrastructure.cache.idservice.RedisIdUtil;
import com.neulogistics.infrastructure.common.serviceresult.BaseResponse;
import com.neulogistics.infrastructure.common.serviceresult.ResultUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Component
public class PlaceOrderCommandHandler implements IRequestHandler<PlaceOrderCommand, BaseResponse<Long>> {

    @Resource
    ICustomerCenterDomainService customerCenterDomainService;

    @Resource
    ICustomerCenterIntegrationEventService customerCenterIntegrationEventService;

    @Resource
    RedisIdUtil redisIdUtil;

    @Value("${spring.application.name}")
    private String appName;

    private final String Order_Id_Key;

    @Resource
    private TransactionTemplate transactionTemplate;

    public PlaceOrderCommandHandler(@Value("${spring.application.name}") String appName) {
        Order_Id_Key = appName + ":" + "orderId";
    }

    @Override
    @ProduceEvent
    public BaseResponse<Long> handle(PlaceOrderCommand command) {
        // todo 检查商品数量是否超过一单容量最大值

        // 根据command创建Order实体
        Long orderId = redisIdUtil.nextId(Order_Id_Key);
        Integer customerId = command.getCustomerId();
        List<OrderItem> orderItems = command.getOrderItems();
        String orderRemark = command.getOrderRemark();
        Address receiverAddress = command.getReceiverAddress();
        String receiverName = command.getReceiverName();
        String receiverPhone = command.getReceiverPhone();
        Integer optInvoice = command.getOptInvoice();
        Date expDeliveryTime = command.getExpDeliveryTime();

        Order order = new Order(orderId, OrderType.Delivery, customerId, orderItems,
                orderRemark, receiverAddress, receiverName,
                receiverPhone, optInvoice, expDeliveryTime);

        // 开启事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
            try {
                // 调用领域服务，下单
                customerCenterDomainService.placeOrder(order);

                // 生成集成事件id并创建事件
                Long eventId = redisIdUtil.nextId(IntegrationEventConstant.Integration_Event_Id_Key);
                OrderPlacedIntegrationEvent orderPlacedIntegrationEvent = new OrderPlacedIntegrationEvent(eventId);
                BeanUtils.copyProperties(order, orderPlacedIntegrationEvent);

                // 获取当前事务id，并保存该集成事件
                Long transactionId = ThreadLocalService.transactionId.get();
                customerCenterIntegrationEventService.addAndSaveEvent(orderPlacedIntegrationEvent, transactionId);
            } catch (Exception e){
                // 触发回滚
                throw new RuntimeException(e.getMessage());
            }
            }
        });

        return ResultUtils.success(orderId);
    }
}
